package com.zhongen.auth.support.mini;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.zhongen.admin.api.dto.UserDTO;
import com.zhongen.admin.api.dto.UserInfo;
import com.zhongen.admin.api.feign.RemoteUserService;
import com.zhongen.auth.support.base.OAuth2ResourceOwnerBaseAuthenticationProvider;
import com.zhongen.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationProvider;
import com.zhongen.common.core.constant.SecurityConstants;
import com.zhongen.common.core.util.R;
import com.zhongen.common.core.util.SpringContextHolder;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.OAuth2Token;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;

import java.util.Map;

/**
 * 处理小程序授权
 */
public class OAuth2ResourceOwnerMiniAuthenticationProvider
		extends OAuth2ResourceOwnerBaseAuthenticationProvider<OAuth2ResourceOwnerMiniAuthenticationToken> {

	private static final Logger LOGGER = LogManager.getLogger(OAuth2ResourceOwnerPasswordAuthenticationProvider.class);

	private final WxMaService wxService;

	private final RemoteUserService remoteUserService;

	public OAuth2ResourceOwnerMiniAuthenticationProvider(AuthenticationManager authenticationManager,
			OAuth2AuthorizationService authorizationService,
			OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
		super(authenticationManager, authorizationService, tokenGenerator);
		wxService = SpringContextHolder.getBean(WxMaService.class);
		remoteUserService = SpringContextHolder.getBean(RemoteUserService.class);
	}

	@Override
	public UsernamePasswordAuthenticationToken buildToken(Map<String, Object> reqParameters) {
		String phoneCode = (String) reqParameters.get(SecurityConstants.MINI_PARAMETER_CODE);
		// 获得对应的手机号信息
		WxMaPhoneNumberInfo phoneNumberInfo;
		try {
			phoneNumberInfo = wxService.getUserService().getPhoneNoInfo(phoneCode);
		}
		catch (WxErrorException e) {
			throw new RuntimeException(e);
		}
		String phoneNumber = phoneNumberInfo.getPurePhoneNumber();
		UserDTO userDTO = new UserDTO();
		userDTO.setPhone(phoneNumber);
		// 获得用户信息
		R<UserInfo> info = remoteUserService.info(userDTO, SecurityConstants.FROM_IN);
		if (info.getData() == null) {
			userDTO.setUsername(phoneNumber);
			userDTO.setPassword("123456");
			userDTO.setName("小程序用户");
			userDTO.setNickname("小程序用户");
			// 如果用户不存在，一键登录将自动创建用户
			R<Boolean> result = remoteUserService.createUser(userDTO, SecurityConstants.FROM_IN);
			if (!result.getData()) {
				throw new RuntimeException("创建用户失败");
			}
		}
		return new UsernamePasswordAuthenticationToken(phoneNumber, null);
	}

	@Override
	public boolean supports(Class<?> authentication) {
		boolean supports = OAuth2ResourceOwnerMiniAuthenticationToken.class.isAssignableFrom(authentication);
		LOGGER.debug("supports authentication=" + authentication + " returning " + supports);
		return supports;
	}

	@Override
	public void checkClient(RegisteredClient registeredClient) {
		assert registeredClient != null;
		if (!registeredClient.getAuthorizationGrantTypes()
			.contains(new AuthorizationGrantType(SecurityConstants.MINI))) {
			throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
		}
	}

}
